use anyhow::anyhow;
use anyhow::Result;
use eastmoney;
use eastmoney::fund::funds_etf::FundEtf;
use eastmoney::fund::funds_etf::FundEtfData;
use fudata::db;
use fudata::model::security;
use fudata::model::FudaRecord;
use log::debug;
use log::error;
use log::info;
use serde_json::Value;

use crate::helper;
pub async fn update_etf_list_all_from_eastmoney() -> Result<()> {
    let mut pn = 1;
    let pz = 1000;

    loop {
        info!(
            "(funds_craw::update_etf_list_all_from_eastmoney) start! for page: {pn} page-size: {pz}"
        );
        let rs = update_etf_list_page_from_eastmoney(pn, pz).await;
        match rs {
            Ok(records) => {
                if records.is_empty() {
                    info!("debug No more records available; exit the loop");

                    break; // No more records available; exit the loop
                }
                pn += 1; // Increment the page number for the next request
                debug!("..{}", pn);
            }
            Err(error) => {
                // 错误处理: 打印错误日志并采取相应措施
                error!("Update error on page {}: {:?}", pn, error);

                return Err(error); // An error occurred; exit the loop
            }
        }
        info!(
            "(funds_craw::update_etf_list_all_from_eastmoney) /end! for page: {pn} page-size: {pz}"
        );
    }

    Ok(())
}

/// Update ETF fund list: 场内交易基金排行
///
/// pn: u16, page index, start from 1
///
/// pz: u16, page size
///
pub async fn update_etf_list_page_from_eastmoney(pn: u16, pz: u16) -> Result<Vec<FudaRecord>> {
    let fund_etf = eastmoney::fund::funds_etf::FundEtf
        ::fund_etf_list(pn, pz).await
        .map_err(|err| anyhow!(err.to_string()))?;
    let mut updates = Vec::new();

    if let FundEtf { data: Some(FundEtfData { diff, .. }), .. } = fund_etf {
        for (_idx, df) in diff.iter().enumerate() {
            match (&df.f12, &df.f14) {
                (Some(Value::String(code)), Some(Value::String(name))) => {
                    let market = helper::get_stock_market(&code); //.map_err(|err| anyhow!(err.to_string()));
                    match market {
                        Ok(mkt) => {
                            debug!("{mkt}.{}.{}, {}", security::SecurityType::ETF, code, name);

                            let security = security::Security {
                                market: mkt,
                                type_: security::SecurityType::ETF,
                                symbol: code.to_owned(),
                                name: Some(name.to_owned()),
                                ..Default::default()
                            };

                            // Update a security record with a specific id
                            let updated: Option<FudaRecord> = db::security::upsert(
                                &security
                            ).await?;

                            if let Some(u) = updated {
                                updates.push(u);
                            }
                        }
                        Err(e) => error!("\n*** update_etf_list_from_eastmoney, {}", e),
                    }
                }
                _ => {
                    // Handle the case where either diff.f12 or diff.f14 is None
                    // or if the unwrapping fails
                    error!(
                        "Error: Missing code:diff.f12={:?} or name:diff.f14={:?}",
                        df.f12,
                        df.f14
                    );
                }
            }
        }
    }

    Ok(updates)
}

#[cfg(test)]
mod test {
    use crate::fund::etfs_craw;

    use chrono::{ Duration, Local };

    use log::debug;
    use serde::Deserialize;

    #[derive(Debug, Deserialize, PartialEq)]
    struct Count {
        count: u64,
    }

    #[tokio::test]
    async fn test_update_etf_list_from_eastmoney() {
        pretty_env_logger::init_timed();
        let _ = fudata::db::init().await.unwrap();

        let mut pn = 1;
        let pz = 100;
        while pn < 1000 {
            let rs = etfs_craw::update_etf_list_page_from_eastmoney(pn, pz).await;

            match rs {
                Ok(records) => {
                    if records.is_empty() {
                        break; // No more records available; exit the loop
                    }
                    pn += 1; // Increment the page number for the next request
                    println!("..{}", pn);
                }
                Err(error) => {
                    // 错误处理: 打印错误日志并采取相应措施
                    println!("Update error on page {}: {:?}", pn, error);
                    break; // An error occurred; exit the loop
                }
            }
        }
    }
}
